{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "wJcYs_ERTnnI"
      },
      "source": [
        "##### Copyright 2018 The TensorFlow Authors."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "cellView": "form",
        "id": "HMUDt0CiUJk9"
      },
      "outputs": [],
      "source": [
        "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "# you may not use this file except in compliance with the License.\n",
        "# You may obtain a copy of the License at\n",
        "#\n",
        "# https://www.apache.org/licenses/LICENSE-2.0\n",
        "#\n",
        "# Unless required by applicable law or agreed to in writing, software\n",
        "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "# See the License for the specific language governing permissions and\n",
        "# limitations under the License."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "77z2OchJTk0l"
      },
      "source": [
        "# TensorFlow 1 のコードを TensorFlow 2 に移行する\n",
        "\n",
        "<table class=\"tfo-notebook-buttons\" align=\"left\">\n",
        "  <td><a target=\"_blank\" href=\"https://www.tensorflow.org/guide/migrate\">     <img src=\"https://www.tensorflow.org/images/tf_logo_32px.png\">TensorFlow.org で表示</a></td>\n",
        "  <td><a target=\"_blank\" href=\"https://colab.research.google.com/github/tensorflow/docs-l10n/blob/master/site/ja/guide/migrate.ipynb\">     <img src=\"https://www.tensorflow.org/images/colab_logo_32px.png\">     Google Colab で実行</a></td>\n",
        "  <td><a target=\"_blank\" href=\"https://github.com/tensorflow/docs-l10n/blob/master/site/ja/guide/migrate.ipynb\">     <img src=\"https://www.tensorflow.org/images/GitHub-Mark-32px.png\">GitHub でソースを表示</a></td>\n",
        "  <td><a href=\"https://storage.googleapis.com/tensorflow_docs/docs-l10n/site/ja/guide/migrate.ipynb\"><img src=\"https://www.tensorflow.org/images/download_logo_32px.png\">ノートブックをダウンロード</a></td>\n",
        "</table>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "meUTrR4I6m1C"
      },
      "source": [
        "本ドキュメントは、低レベル TensorFlow API のユーザーを対象としています。高レベル API（`tf.keras`）をご使用の場合は、コードをTensorFlow 2.0 と完全互換にするためのアクションは殆どまたは全く必要ありません。\n",
        "\n",
        "- [オプティマイザのデフォルトの学習率](#keras_optimizer_lr)を確認してください。\n",
        "- メトリクスが記録される「名前」が[変更されている可能性がある](#keras_metric_names)ことに注意してください。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "C0V10enS1_WU"
      },
      "source": [
        "TensorFlow 2.0 で 1.X のコードを未修正で実行することは、（[contrib を除き](https://github.com/tensorflow/community/blob/master/rfcs/20180907-contrib-sunset.md)）依然として可能です。\n",
        "\n",
        "```\n",
        "import tensorflow.compat.v1 as tf tf.disable_v2_behavior()\n",
        "```\n",
        "\n",
        "しかし、これでは TensorFlow 2.0 で追加された改善の多くを活用できません。このガイドでは、コードのアップグレード、さらなる単純化、パフォーマンス向上、そしてより容易なメンテナンスについて説明します。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "GUp_x0bOgaac"
      },
      "source": [
        "## 自動変換スクリプト\n",
        "\n",
        "このドキュメントで説明される変更を実装する前に行うべき最初のステップは、[アップグレードスクリプト](./upgrade.md)を実行してみることです。\n",
        "\n",
        "これはコードを TensorFlow 2.0 にアップグレードする際の初期パスとしては十分ですが、2.0 特有のコードに変換するわけではありません。コードは依然として`tf.compat.v1`エンドポイントを使用して、プレースホルダー、セッション、コレクション、その他 1.x- スタイルの機能へのアクセスが可能です。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "0w5LiSYsy1mh"
      },
      "source": [
        "## トップレベルの動作の変更\n",
        "\n",
        "`tf.compat.v1.disable_v2_behavior()`を使用することで TensorFlow 2.0 でコードが機能する場合でも、対処すべきグローバルな動作の変更があります。主な変更点は次のとおりです。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "1y-W0Mz_zB6Y"
      },
      "source": [
        "- *Eager execution、`v1.enable_eager_execution()`* : 暗黙的に`tf.Graph`を使用するコードは失敗します。このコードは必ず`with tf.Graph().as_default()`コンテキストでラップしてください。\n",
        "\n",
        "- *リソース変数、`v1.enable_resource_variables()`*: 一部のコードは、TensorFlow 参照変数によって有効化される非決定的な動作に依存する場合があります。 リソース変数は書き込み中にロックされるため、より直感的な一貫性を保証します。\n",
        "\n",
        "    - これによりエッジケースでの動作が変わる場合があります。\n",
        "    - これにより余分なコピーが作成されるため、メモリ使用量が増える可能性があります。\n",
        "    - これを無効にするには、`use_resource=False`を`tf.Variable`コンストラクタに渡します。\n",
        "\n",
        "- *テンソルの形状、`v1.enable_v2_tensorshape()`*: TensorFlow 2.0 は、テンソルの形状の動作を簡略化されており、`t.shape[0].value`の代わりに`t.shape[0]`とすることができます。簡単な変更なので、すぐに修正しておくことをお勧めします。例については [TensorShape](#tensorshape) をご覧ください。\n",
        "\n",
        "- *制御フロー、`v1.enable_control_flow_v2()`*: TensorFlow 2.0 制御フローの実装が簡略化されたため、さまざまなグラフ表現を生成します。問題が生じた場合には、[バグを報告](https://github.com/tensorflow/tensorflow/issues)してください。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "_Ni9zLLvwcOR"
      },
      "source": [
        "## コードを 2.0 ネイティブにする\n",
        "\n",
        "このガイドでは、TensorFlow 1.x のコードを TensorFlow 2.0 に変換する幾つかの例をウォークスルーします。これらの変更によって、コードがパフォーマンスの最適化および簡略化された API 呼び出しを活用できるようになります。\n",
        "\n",
        "それぞれのケースのパターンは次のとおりです。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "uP0O8Pc45LNs"
      },
      "source": [
        "### 1. `v1.Session.run`呼び出しを置き換える\n",
        "\n",
        "すべての`v1.Session.run`呼び出しは、Python 関数で置き換える必要があります。\n",
        "\n",
        "- `feed_dict`および`v1.placeholder`は関数の引数になります。\n",
        "- `fetches`は関数の戻り値になります。\n",
        "- eager execution では、`pdb`などの標準的な Python ツールを使用して、変換中に簡単にデバッグできます。\n",
        "\n",
        "次に、`tf.function`デコレータを追加して、グラフで効率的に実行できるようにします。 この機能についての詳細は、[AutoGraph ガイド](function.ipynb)をご覧ください。\n",
        "\n",
        "注意点:\n",
        "\n",
        "- `v1.Session.run`とは異なり、`tf.function`は固定のリターンシグネチャを持ち、常にすべての出力を返します。これによってパフォーマンスの問題が生じる場合は、2 つの個別の関数を作成します。\n",
        "\n",
        "- `tf.control_dependencies`または同様の演算は必要ありません。`tf.function`は、記述された順序で実行されたかのように動作します。例えば、`tf.Variable`割り当てと`tf.assert`は自動的に実行されます。\n",
        "\n",
        "[変換モデルセクション{/ a0}には、この変換プロセスの実際の例が含まれています。](#converting_models)\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "jlBOqROL5NmN"
      },
      "source": [
        "### 2. Python オブジェクトを変数と損失の追跡に使用する\n",
        "\n",
        "TensorFlow 2.0 では、いかなる名前ベースの変数追跡も全く推奨されていません。 変数の追跡には Python オブジェクトを使用します。\n",
        "\n",
        "`v1.get_variable`の代わりに`tf.Variable`を使用してください。\n",
        "\n",
        "すべての`v1.variable_scope`は Python オブジェクトに変換が可能です。通常は次のうちの 1 つになります。\n",
        "\n",
        "- `tf.keras.layers.Layer`\n",
        "- `tf.keras.Model`\n",
        "- `tf.Module`\n",
        "\n",
        "`tf.Graph.get_collection(tf.GraphKeys.VARIABLES)`などの変数のリストを集める必要がある場合には、`Layer`および`Model`オブジェクトの`.variables`と`.trainable_variables`属性を使用します。\n",
        "\n",
        "これら`Layer`クラスと`Model`クラスは、グローバルコレクションの必要性を除去した別のプロパティを幾つか実装します。`.losses`プロパティは、`tf.GraphKeys.LOSSES`コレクション使用の置き換えとなります。\n",
        "\n",
        "詳細は [Keras ガイド](keras.ipynb)をご覧ください。\n",
        "\n",
        "警告 : 多くの`tf.compat.v1`シンボルはグローバルコレクションを暗黙的に使用しています。\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "rGFhBzoF5FIq"
      },
      "source": [
        "### 3. トレーニングループをアップグレードする\n",
        "\n",
        "ご利用のユースケースで動作する最高レベルの API を使用してください。独自のトレーニングループを構築するよりも `tf.keras.Model.fit` の選択を推奨します。\n",
        "\n",
        "これらの高レベル関数は、独自のトレーニングループを書く場合に見落とされやすい多くの低レベル詳細を管理します。例えば、それらは自動的に正則化損失を集めて、モデルを呼び出す時に`training=True`引数を設定します。\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "oaY37_6L4la5"
      },
      "source": [
        "### 4. データ入力パイプラインをアップグレードする\n",
        "\n",
        "データ入力には`tf.data`データセットを使用してください。それらのオブジェクトは効率的で、表現力があり、TensorFlow とうまく統合します。\n",
        "\n",
        "次のように、`tf.keras.Model.fit`メソッドに直接渡すことができます。\n",
        "\n",
        "```\n",
        "model.fit(dataset, epochs=5)\n",
        "```\n",
        "\n",
        "また、標準的な Python で直接にイテレートすることもできます。\n",
        "\n",
        "```\n",
        "for example_batch, label_batch in dataset:     break\n",
        "```\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "_Mwsd0SK4oIs"
      },
      "source": [
        "### 5. `compat.v1`シンボルを移行する\n",
        "\n",
        "`tf.compat.v1`モジュールには、元のセマンティクスを持つ完全な TensorFlow 1.x API が含まれています。\n",
        "\n",
        "[TensorFlow 2 アップグレードスクリプト](upgrade.ipynb)は、変換が安全な場合、つまり 2.0 バージョンの動作が完全に同等であると判断できる場合は、シンボルを 2.0 と同等のものに変換します。（例えば、これらは同じ関数なので、`v1.arg_max`の名前を`tf.argmax`に変更します。）\n",
        "\n",
        "コードの一部を使用してアップグレードスクリプトを実行した後に、`compat.v1`が頻出する可能性があります。 コードを調べ、それらを手動で同等の 2.0 のコードに変換する価値はあります。（該当するものがある場合には、ログに表示されているはずです。）"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "X_ilfTGJ4Yml"
      },
      "source": [
        "## モデルを変換する"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "FB99sqHX2Q5m"
      },
      "source": [
        "### 低レベル変数 ＆ 演算子実行\n",
        "\n",
        "低レベル API の使用例を以下に示します。\n",
        "\n",
        "- 変数スコープを使用して再利用を制御する。\n",
        "\n",
        "- `v1.get_variable`で変数を作成する。\n",
        "\n",
        "- コレクションに明示的にアクセスする。\n",
        "\n",
        "- 次のようなメソッドでコレクションに暗黙的にアクセスする。\n",
        "\n",
        "    - `v1.global_variables`\n",
        "    - `v1.losses.get_regularization_loss`\n",
        "\n",
        "- `v1.placeholder` を使用してグラフ入力のセットアップをする。\n",
        "\n",
        "- `Session.run`でグラフを実行する。\n",
        "\n",
        "- 変数を手動で初期化する。\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "e582IjyF2eje"
      },
      "source": [
        "#### 変換前\n",
        "\n",
        "TensorFlow 1.x を使用したコードでは、これらのパターンは以下のように表示されます。\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "hM7IJ-VHYlHK"
      },
      "outputs": [],
      "source": [
        "import tensorflow as tf\n",
        "import tensorflow.compat.v1 as v1\n",
        "\n",
        "import tensorflow_datasets as tfds"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "JkLMlYzxU5F1"
      },
      "outputs": [],
      "source": [
        "g = v1.Graph()\n",
        "\n",
        "with g.as_default():\n",
        "  in_a = v1.placeholder(dtype=v1.float32, shape=(2))\n",
        "  in_b = v1.placeholder(dtype=v1.float32, shape=(2))\n",
        "\n",
        "  def forward(x):\n",
        "    with v1.variable_scope(\"matmul\", reuse=v1.AUTO_REUSE):\n",
        "      W = v1.get_variable(\"W\", initializer=v1.ones(shape=(2,2)),\n",
        "                          regularizer=lambda x:tf.reduce_mean(x**2))\n",
        "      b = v1.get_variable(\"b\", initializer=v1.zeros(shape=(2)))\n",
        "      return W * x + b\n",
        "\n",
        "  out_a = forward(in_a)\n",
        "  out_b = forward(in_b)\n",
        "  reg_loss=v1.losses.get_regularization_loss(scope=\"matmul\")\n",
        "\n",
        "with v1.Session(graph=g) as sess:\n",
        "  sess.run(v1.global_variables_initializer())\n",
        "  outs = sess.run([out_a, out_b, reg_loss],\n",
        "      \t        feed_dict={in_a: [1, 0], in_b: [0, 1]})\n",
        "\n",
        "print(outs[0])\n",
        "print()\n",
        "print(outs[1])\n",
        "print()\n",
        "print(outs[2])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "QARwz4Xd2lc2"
      },
      "source": [
        "#### 変換後"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "x0AVzBFRBPcU"
      },
      "source": [
        "変換されたコードでは :\n",
        "\n",
        "- 変数はローカル Python オブジェクトです。\n",
        "- `forward`関数は依然として計算を定義します。\n",
        "- `Session.run`呼び出しは`forward`への呼び出しに置き換えられます。\n",
        "- パフォーマンス向上のためにオプションで`tf.function`デコレータを追加可能です。\n",
        "- どのグローバルコレクションも参照せず、正則化は手動で計算されます。\n",
        "- **セッションやプレースホルダーはありません。**"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "lXEZoLMP2cWJ"
      },
      "outputs": [],
      "source": [
        "W = tf.Variable(tf.ones(shape=(2,2)), name=\"W\")\n",
        "b = tf.Variable(tf.zeros(shape=(2)), name=\"b\")\n",
        "\n",
        "@tf.function\n",
        "def forward(x):\n",
        "  return W * x + b\n",
        "\n",
        "out_a = forward([1,0])\n",
        "print(out_a)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "YmE96A_1jZTg"
      },
      "outputs": [],
      "source": [
        "out_b = forward([0,1])\n",
        "\n",
        "regularizer = tf.keras.regularizers.l2(0.04)\n",
        "reg_loss=regularizer(W)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ycDxY9nL268-"
      },
      "source": [
        "### `tf.layers`ベースのモデル"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "K-bIk7wL48U7"
      },
      "source": [
        "`v1.layers`モジュールは、変数を定義および再利用する`v1.variable_scope`に依存するレイヤー関数を含めるために使用されます。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "8I_qKpT73KyM"
      },
      "source": [
        "#### 変換前\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "1o-FGPkfZMdM"
      },
      "outputs": [],
      "source": [
        "def model(x, training, scope='model'):\n",
        "  with v1.variable_scope(scope, reuse=v1.AUTO_REUSE):\n",
        "    x = v1.layers.conv2d(x, 32, 3, activation=v1.nn.relu,\n",
        "          kernel_regularizer=lambda x:0.004*tf.reduce_mean(x**2))\n",
        "    x = v1.layers.max_pooling2d(x, (2, 2), 1)\n",
        "    x = v1.layers.flatten(x)\n",
        "    x = v1.layers.dropout(x, 0.1, training=training)\n",
        "    x = v1.layers.dense(x, 64, activation=v1.nn.relu)\n",
        "    x = v1.layers.batch_normalization(x, training=training)\n",
        "    x = v1.layers.dense(x, 10)\n",
        "    return x"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "AxtmOazcat6E"
      },
      "outputs": [],
      "source": [
        "train_data = tf.ones(shape=(1, 28, 28, 1))\n",
        "test_data = tf.ones(shape=(1, 28, 28, 1))\n",
        "\n",
        "train_out = model(train_data, training=True)\n",
        "test_out = model(test_data, training=False)\n",
        "\n",
        "print(train_out)\n",
        "print()\n",
        "print(test_out)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "b8_Ii7CQ3fK-"
      },
      "source": [
        "#### 変換後"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "BsAseSMfB9XN"
      },
      "source": [
        "- レイヤーの単純なスタックが `tf.keras.Sequential`にぴったり収まります。（より複雑なモデルについては[カスタムレイヤーとモデル](keras/custom_layers_and_models.ipynb)および[ Functional API ](keras/functional.ipynb)をご覧ください。）\n",
        "- モデルが変数と正則化損失を追跡します。\n",
        "- `v1.layers`から`tf.keras.layers`への直接的なマッピングがあるため、変換は一対一対応でした。\n",
        "\n",
        "ほとんどの引数はそのままです。しかし、以下の点は異なります。\n",
        "\n",
        "- `training`引数は、それが実行される時点でモデルによって各レイヤーに渡されます。\n",
        "- 元の`model`関数への最初の引数（入力 `x`）はなくなりました。これはオブジェクトレイヤーがモデルの呼び出しからモデルの構築を分離するためです。\n",
        "\n",
        "また以下にも注意してください。\n",
        "\n",
        "- `tf.contrib`からの初期化子の正則化子を使用している場合は、他よりも多くの引数変更があります。\n",
        "- コードはコレクションに書き込みを行わないため、`v1.losses.get_regularization_loss`などの関数はそれらの値を返さなくなり、トレーニングループが壊れる可能性があります。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "DLAPORrN3lct"
      },
      "outputs": [],
      "source": [
        "model = tf.keras.Sequential([\n",
        "    tf.keras.layers.Conv2D(32, 3, activation='relu',\n",
        "                           kernel_regularizer=tf.keras.regularizers.l2(0.04),\n",
        "                           input_shape=(28, 28, 1)),\n",
        "    tf.keras.layers.MaxPooling2D(),\n",
        "    tf.keras.layers.Flatten(),\n",
        "    tf.keras.layers.Dropout(0.1),\n",
        "    tf.keras.layers.Dense(64, activation='relu'),\n",
        "    tf.keras.layers.BatchNormalization(),\n",
        "    tf.keras.layers.Dense(10)\n",
        "])\n",
        "\n",
        "train_data = tf.ones(shape=(1, 28, 28, 1))\n",
        "test_data = tf.ones(shape=(1, 28, 28, 1))"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "6nWh6IXvkMKv"
      },
      "outputs": [],
      "source": [
        "train_out = model(train_data, training=True)\n",
        "print(train_out)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "YnAdIDLlj3go"
      },
      "outputs": [],
      "source": [
        "test_out = model(test_data, training=False)\n",
        "print(test_out)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "sAgqwCJBMx_x"
      },
      "outputs": [],
      "source": [
        "# Here are all the trainable variables.\n",
        "len(model.trainable_variables)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "uX6knaYMNM8p"
      },
      "outputs": [],
      "source": [
        "# Here is the regularization loss.\n",
        "model.losses"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "9moqw5E_4Cwl"
      },
      "source": [
        "### 変数と`v1.layers`の混在\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "80DEsImmq6VX"
      },
      "source": [
        "既存のコードは低レベルの TensorFlow 1.x 変数と演算子に高レベルの`v1.layers`が混ざっていることがよくあります。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "oZe9L6RR4OcP"
      },
      "source": [
        "#### 変換前\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "c9JAKRa1bA5u"
      },
      "outputs": [],
      "source": [
        "def model(x, training, scope='model'):\n",
        "  with v1.variable_scope(scope, reuse=v1.AUTO_REUSE):\n",
        "    W = v1.get_variable(\n",
        "      \"W\", dtype=v1.float32,\n",
        "      initializer=v1.ones(shape=x.shape),\n",
        "      regularizer=lambda x:0.004*tf.reduce_mean(x**2),\n",
        "      trainable=True)\n",
        "    if training:\n",
        "      x = x + W\n",
        "    else:\n",
        "      x = x + W * 0.5\n",
        "    x = v1.layers.conv2d(x, 32, 3, activation=tf.nn.relu)\n",
        "    x = v1.layers.max_pooling2d(x, (2, 2), 1)\n",
        "    x = v1.layers.flatten(x)\n",
        "    return x\n",
        "\n",
        "train_out = model(train_data, training=True)\n",
        "test_out = model(test_data, training=False)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "y6ORX7cD4TkD"
      },
      "source": [
        "#### 変換後"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "2BaRwog5CBpz"
      },
      "source": [
        "このコードを変換するには、前の例で示したレイヤーからレイヤーへのマッピングのパターンに従います。\n",
        "\n",
        "一般的なパターンは次の通りです。\n",
        "\n",
        "- `__init__`でレイヤーパラメータを収集する。\n",
        "- `build`で変数を構築する。\n",
        "- `call`で計算を実行し、結果を返す。\n",
        "\n",
        "`v1.variable_scope`は事実上それ自身のレイヤーです。従って`tf.keras.layers.Layer`として書き直します。詳細は[ガイド](keras/custom_layers_and_models.ipynb)をご覧ください。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "YcCAjNuP4NVh"
      },
      "outputs": [],
      "source": [
        "# Create a custom layer for part of the model\n",
        "class CustomLayer(tf.keras.layers.Layer):\n",
        "  def __init__(self, *args, **kwargs):\n",
        "    super(CustomLayer, self).__init__(*args, **kwargs)\n",
        "\n",
        "  def build(self, input_shape):\n",
        "    self.w = self.add_weight(\n",
        "        shape=input_shape[1:],\n",
        "        dtype=tf.float32,\n",
        "        initializer=tf.keras.initializers.ones(),\n",
        "        regularizer=tf.keras.regularizers.l2(0.02),\n",
        "        trainable=True)\n",
        "\n",
        "  # Call method will sometimes get used in graph mode,\n",
        "  # training will get turned into a tensor\n",
        "  @tf.function\n",
        "  def call(self, inputs, training=None):\n",
        "    if training:\n",
        "      return inputs + self.w\n",
        "    else:\n",
        "      return inputs + self.w * 0.5"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "dR_QO6_wBgMm"
      },
      "outputs": [],
      "source": [
        "custom_layer = CustomLayer()\n",
        "print(custom_layer([1]).numpy())\n",
        "print(custom_layer([1], training=True).numpy())"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "VzqaIf4E42oY"
      },
      "outputs": [],
      "source": [
        "train_data = tf.ones(shape=(1, 28, 28, 1))\n",
        "test_data = tf.ones(shape=(1, 28, 28, 1))\n",
        "\n",
        "# Build the model including the custom layer\n",
        "model = tf.keras.Sequential([\n",
        "    CustomLayer(input_shape=(28, 28, 1)),\n",
        "    tf.keras.layers.Conv2D(32, 3, activation='relu'),\n",
        "    tf.keras.layers.MaxPooling2D(),\n",
        "    tf.keras.layers.Flatten(),\n",
        "])\n",
        "\n",
        "train_out = model(train_data, training=True)\n",
        "test_out = model(test_data, training=False)\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "dS5ed_jjOkvh"
      },
      "source": [
        "注意点:\n",
        "\n",
        "- サブクラス化された Keras モデルとレイヤーは v1 グラフ（自動制御依存性なし）と eager モードの両方で実行される必要があります。\n",
        "\n",
        "    - `call()`を`tf.function()`にラップして、AutoGraph と自動制御依存性を得るようにします。\n",
        "\n",
        "- `training`引数を受け取って`call`することを忘れないようにしてください。\n",
        "\n",
        "    - それは`tf.Tensor`である場合があります。\n",
        "    - それは Python ブール型である場合があります。\n",
        "\n",
        "- `self.add_weight()`を使用して、コンストラクタまたは`Model.build`でモデル変数を作成します。\n",
        "\n",
        "    - `Model.build`では、入力形状にアクセスできるため、適合する形状で重みを作成できます。\n",
        "    - `tf.keras.layers.Layer.add_weight`を使用すると、Keras が変数と正則化損失を追跡できるようになります。\n",
        "\n",
        "- オブジェクトに`tf.Tensors`を保持してはいけません。\n",
        "\n",
        "    - それらは`tf.function`または eager コンテキスト内のいずれかで作成される可能性がありますが、それらのテンソルは異なる振る舞いをします。\n",
        "    - 状態には`tf.Variable`を使用してください。これは常に両方のコンテキストから使用可能です。\n",
        "    - `tf.Tensors`は中間値専用です。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ulaB1ymO4pw5"
      },
      "source": [
        "### Slim & contrib.layers に関する注意\n",
        "\n",
        "古い TensorFlow 1.x コードの大部分は [Slim](https://ai.googleblog.com/2016/08/tf-slim-high-level-library-to-define.html) ライブラリを使用しており、これは`tf.contrib.layers`として TensorFlow 1.x でパッケージ化されていました。 `contrib`モジュールに関しては、TensorFlow 2.0 では`tf.compat.v1`内でも、あっても利用できなくなりました。Slim を使用したコードの TensorFlow 2.0 への変換は、`v1.layers`を使用したレポジトリの変換よりも複雑です。現実的には、まず最初に Slim コードを`v1.layers`に変換してから Keras に変換するほうが賢明かもしれません。\n",
        "\n",
        "- `arg_scopes`を除去します。すべての引数は明示的である必要があります。\n",
        "- それらを使用する場合、 `normalizer_fn`と`activation_fn`をそれら自身のレイヤーに分割します。\n",
        "- 分離可能な畳み込みレイヤーは 1 つまたはそれ以上の異なる Keras レイヤー（深さ的な、ポイント的な、分離可能な Keras レイヤー）にマップします。\n",
        "- Slim と`v1.layers`には異なる引数名とデフォルト値があります。\n",
        "- 一部の引数には異なるスケールがあります。\n",
        "- Slim 事前トレーニング済みモデルを使用する場合は、`tf.keras.applications`から Keras 事前トレーニング済みモデル、または元の Slim コードからエクスポートされた [TensorFlow ハブ](https://tfhub.dev/s?q=slim%20tf2)の TensorFlow 2 SavedModel をお試しください。\n",
        "\n",
        "一部の`tf.contrib`レイヤーはコアの TensorFlow に移動されていない可能性がありますが、代わりに [TensorFlow アドオンパッケージ](https://github.com/tensorflow/addons)に移動されています。\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "1w72KrXm4yZR"
      },
      "source": [
        "## トレーニング"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "56PQxTgy2bpI"
      },
      "source": [
        "`tf.keras`モデルにデータを供給する方法は沢山あります。それらは Python ジェネレータと Numpy 配列を入力として受け取ります。\n",
        "\n",
        "モデルへのデータ供給方法として推奨するのは、データ操作用の高パフォーマンスクラスのコレクションを含む`tf.data`パッケージの使用です。\n",
        "\n",
        "依然として`tf.queue`を使用している場合、これらは入力パイプラインとしてではなく、データ構造としてのみサポートされます。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "m6htasZ7iBB4"
      },
      "source": [
        "### データセットを使用する"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "loTPH2Pz4_Oj"
      },
      "source": [
        "[TensorFlow Dataset](https://tensorflow.org/datasets) パッケージ（`tfds`）には、事前定義されたデータセットを`tf.data.Dataset`オブジェクトとして読み込むためのユーティリティが含まれています。\n",
        "\n",
        "この例として、`tfds`を使用して MNISTdataset を読み込んでみましょう。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "BMgxaLH74_s-"
      },
      "outputs": [],
      "source": [
        "datasets, info = tfds.load(name='mnist', with_info=True, as_supervised=True)\n",
        "mnist_train, mnist_test = datasets['train'], datasets['test']"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "hPJhEuvj5VfR"
      },
      "source": [
        "次に、トレーニング用のデータを準備します。\n",
        "\n",
        "- 各画像をリスケールする。\n",
        "- 例の順序をシャッフルする。\n",
        "- 画像とラベルのバッチを集める。\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "StBRHtJM2S7o"
      },
      "outputs": [],
      "source": [
        "BUFFER_SIZE = 10 # Use a much larger value for real code.\n",
        "BATCH_SIZE = 64\n",
        "NUM_EPOCHS = 5\n",
        "\n",
        "\n",
        "def scale(image, label):\n",
        "  image = tf.cast(image, tf.float32)\n",
        "  image /= 255\n",
        "\n",
        "  return image, label"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "SKq14zKKFAdv"
      },
      "source": [
        "例を短く保つために、データセットをトリミングして 5 バッチのみを返すようにします。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "_J-o4YjG2mkM"
      },
      "outputs": [],
      "source": [
        "train_data = mnist_train.map(scale).shuffle(BUFFER_SIZE).batch(BATCH_SIZE)\n",
        "test_data = mnist_test.map(scale).batch(BATCH_SIZE)\n",
        "\n",
        "STEPS_PER_EPOCH = 5\n",
        "\n",
        "train_data = train_data.take(STEPS_PER_EPOCH)\n",
        "test_data = test_data.take(STEPS_PER_EPOCH)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "XEqdkH54VM6c"
      },
      "outputs": [],
      "source": [
        "image_batch, label_batch = next(iter(train_data))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "mSev7vZC5GJB"
      },
      "source": [
        "### Keras トレーニングループを使用する\n",
        "\n",
        "トレーニングプロセスの低レベル制御が不要な場合は、Keras 組み込みの`fit`、`evaluate`、`predict`メソッドの使用が推奨されます。これらのメソッドは（シーケンシャル、関数型、またはサブクラス化）実装を問わず、モデルをトレーニングするための統一インターフェースを提供します。\n",
        "\n",
        "これらのメソッドには次のような優位点があります。\n",
        "\n",
        "- Numpy 配列、Python ジェネレータ、`tf.data.Datasets`を受け取ります。\n",
        "- 正則化と活性化損失を自動的に適用します。\n",
        "- [マルチデバイストレーニングのために](distributed_training.ipynb)`tf.distribute`をサポートします。\n",
        "- 任意の callable は損失とメトリクスとしてサポートします。\n",
        "- `tf.keras.callbacks.TensorBoard`のようなコールバックとカスタムコールバックをサポートします。\n",
        "- 自動的に TensorFlow グラフを使用し、高性能です。\n",
        "\n",
        "ここに`Dataset`を使用したモデルのトレーニング例を示します。（この機能ついての詳細は[チュートリアル](../tutorials)をご覧ください。）"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "uzHFCzd45Rae"
      },
      "outputs": [],
      "source": [
        "model = tf.keras.Sequential([\n",
        "    tf.keras.layers.Conv2D(32, 3, activation='relu',\n",
        "                           kernel_regularizer=tf.keras.regularizers.l2(0.02),\n",
        "                           input_shape=(28, 28, 1)),\n",
        "    tf.keras.layers.MaxPooling2D(),\n",
        "    tf.keras.layers.Flatten(),\n",
        "    tf.keras.layers.Dropout(0.1),\n",
        "    tf.keras.layers.Dense(64, activation='relu'),\n",
        "    tf.keras.layers.BatchNormalization(),\n",
        "    tf.keras.layers.Dense(10)\n",
        "])\n",
        "\n",
        "# Model is the full model w/o custom layers\n",
        "model.compile(optimizer='adam',\n",
        "              loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),\n",
        "              metrics=['accuracy'])\n",
        "\n",
        "model.fit(train_data, epochs=NUM_EPOCHS)\n",
        "loss, acc = model.evaluate(test_data)\n",
        "\n",
        "print(\"Loss {}, Accuracy {}\".format(loss, acc))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "akpeOb09YBhq"
      },
      "source": [
        "### ループを自分で書く\n",
        "\n",
        "Keras モデルのトレーニングステップは動作していても、そのステップの外でより制御が必要な場合は、データ イテレーション ループで`tf.keras.Model.train_on_batch`メソッドの使用を検討してみてください。\n",
        "\n",
        "`tf.keras.callbacks.Callback`として、多くのものが実装可能であることに留意してください。\n",
        "\n",
        "このメソッドには前のセクションで言及したメソッドの優位点の多くがありますが、外側のループのユーザ制御も与えます。\n",
        "\n",
        "`tf.keras.Model.test_on_batch`または`tf.keras.Model.evaluate`を使用して、トレーニング中のパフォーマンスをチェックすることも可能です。\n",
        "\n",
        "注意 : `train_on_batch`と`test_on_batch`は、デフォルトで単一バッチの損失とメトリクスを返します。`reset_metrics=False`を渡すと累積メトリックを返しますが、必ずメトリックアキュムレータを適切にリセットすることを忘れないようにしてくだい。また、`AUC`のような一部のメトリクスは正しく計算するために`reset_metrics=False`が必要なことも覚えておいてください。\n",
        "\n",
        "上のモデルのトレーニングを続けます。\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "eXr4CyJMtJJ6"
      },
      "outputs": [],
      "source": [
        "# Model is the full model w/o custom layers\n",
        "model.compile(optimizer='adam',\n",
        "              loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),\n",
        "              metrics=['accuracy'])\n",
        "\n",
        "for epoch in range(NUM_EPOCHS):\n",
        "  #Reset the metric accumulators\n",
        "  model.reset_metrics()\n",
        "\n",
        "  for image_batch, label_batch in train_data:\n",
        "    result = model.train_on_batch(image_batch, label_batch)\n",
        "    metrics_names = model.metrics_names\n",
        "    print(\"train: \",\n",
        "          \"{}: {:.3f}\".format(metrics_names[0], result[0]),\n",
        "          \"{}: {:.3f}\".format(metrics_names[1], result[1]))\n",
        "  for image_batch, label_batch in test_data:\n",
        "    result = model.test_on_batch(image_batch, label_batch,\n",
        "                                 # return accumulated metrics\n",
        "                                 reset_metrics=False)\n",
        "  metrics_names = model.metrics_names\n",
        "  print(\"\\neval: \",\n",
        "        \"{}: {:.3f}\".format(metrics_names[0], result[0]),\n",
        "        \"{}: {:.3f}\".format(metrics_names[1], result[1]))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "LQTaHTuK5S5A"
      },
      "source": [
        "<a name=\"custom_loop\"></a>\n",
        "\n",
        "### トレーニングステップをカスタマイズする\n",
        "\n",
        "より多くの柔軟性と制御を必要とする場合、独自のトレーニングループを実装することでそれが可能になります。以下の 3 つのステップを踏みます。\n",
        "\n",
        "1. Python ジェネレータか`tf.data.Dataset`をイテレートして例のバッチを作成します。\n",
        "2. `tf.GradientTape`を使用して勾配を集めます。\n",
        "3. `tf.keras.optimizers`の 1 つを使用して、モデルの変数に重み更新を適用します。\n",
        "\n",
        "留意点:\n",
        "\n",
        "- サブクラス化されたレイヤーとモデルの`call`メソッドには、常に`training`引数を含めます。\n",
        "- `training`引数を確実に正しくセットしてモデルを呼び出します。\n",
        "- 使用方法によっては、モデルがデータのバッチ上で実行されるまでモデル変数は存在しないかもしれません。\n",
        "- モデルの正則化損失などを手動で処理する必要があります。\n",
        "\n",
        "v1 と比べて簡略化されている点に注意してください :\n",
        "\n",
        "- 変数初期化子を実行する必要はありません。作成時に変数は初期化されます。\n",
        "- たとえ`tf.function`演算が eager モードで振る舞う場合でも、手動の制御依存性を追加する必要はありません。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "gQooejfYlQeF"
      },
      "outputs": [],
      "source": [
        "model = tf.keras.Sequential([\n",
        "    tf.keras.layers.Conv2D(32, 3, activation='relu',\n",
        "                           kernel_regularizer=tf.keras.regularizers.l2(0.02),\n",
        "                           input_shape=(28, 28, 1)),\n",
        "    tf.keras.layers.MaxPooling2D(),\n",
        "    tf.keras.layers.Flatten(),\n",
        "    tf.keras.layers.Dropout(0.1),\n",
        "    tf.keras.layers.Dense(64, activation='relu'),\n",
        "    tf.keras.layers.BatchNormalization(),\n",
        "    tf.keras.layers.Dense(10)\n",
        "])\n",
        "\n",
        "optimizer = tf.keras.optimizers.Adam(0.001)\n",
        "loss_fn = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)\n",
        "\n",
        "@tf.function\n",
        "def train_step(inputs, labels):\n",
        "  with tf.GradientTape() as tape:\n",
        "    predictions = model(inputs, training=True)\n",
        "    regularization_loss=tf.math.add_n(model.losses)\n",
        "    pred_loss=loss_fn(labels, predictions)\n",
        "    total_loss=pred_loss + regularization_loss\n",
        "\n",
        "  gradients = tape.gradient(total_loss, model.trainable_variables)\n",
        "  optimizer.apply_gradients(zip(gradients, model.trainable_variables))\n",
        "\n",
        "for epoch in range(NUM_EPOCHS):\n",
        "  for inputs, labels in train_data:\n",
        "    train_step(inputs, labels)\n",
        "  print(\"Finished epoch\", epoch)\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "kS7WW5Z75ve3"
      },
      "source": [
        "### 新しいスタイルのメトリクスと損失\n",
        "\n",
        "TensorFlow 2.0 では、メトリクスと損失はオブジェクトです。逐次実行的に`tf.function`内で動作します。\n",
        "\n",
        "損失オブジェクトは呼び出し可能で、(y_true, y_pred) を引数として期待します。\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "C5_TVrBlbBcy"
      },
      "outputs": [],
      "source": [
        "cce = tf.keras.losses.CategoricalCrossentropy(from_logits=True)\n",
        "cce([[1, 0]], [[-1.0,3.0]]).numpy()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "JFDc1v0XbAyB"
      },
      "source": [
        "メトリックオブジェクトには次のメソッドがあります 。\n",
        "\n",
        "- `Metric.update_state()` — 新しい観測を追加する\n",
        "- `Metric.result()` — 観測値が与えられたとき、メトリックの現在の結果を得る\n",
        "- `Metric.reset_states()` — すべての観測をクリアする\n",
        "\n",
        "オブジェクト自体は呼び出し可能です。呼び出しは`update_state`と同様に新しい観測の状態を更新し、メトリクスの新しい結果を返します。\n",
        "\n",
        "メトリックの変数を手動で初期化する必要はありません。また、TensorFlow 2.0 は自動制御依存性を持つため、それらについても心配不要です。\n",
        "\n",
        "次のコードは、メトリックを使用してカスタムトレーニングループ内で観測される平均損失を追跡します。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "HAbA0fKW58CH"
      },
      "outputs": [],
      "source": [
        "# Create the metrics\n",
        "loss_metric = tf.keras.metrics.Mean(name='train_loss')\n",
        "accuracy_metric = tf.keras.metrics.SparseCategoricalAccuracy(name='train_accuracy')\n",
        "\n",
        "@tf.function\n",
        "def train_step(inputs, labels):\n",
        "  with tf.GradientTape() as tape:\n",
        "    predictions = model(inputs, training=True)\n",
        "    regularization_loss=tf.math.add_n(model.losses)\n",
        "    pred_loss=loss_fn(labels, predictions)\n",
        "    total_loss=pred_loss + regularization_loss\n",
        "\n",
        "  gradients = tape.gradient(total_loss, model.trainable_variables)\n",
        "  optimizer.apply_gradients(zip(gradients, model.trainable_variables))\n",
        "  # Update the metrics\n",
        "  loss_metric.update_state(total_loss)\n",
        "  accuracy_metric.update_state(labels, predictions)\n",
        "\n",
        "\n",
        "for epoch in range(NUM_EPOCHS):\n",
        "  # Reset the metrics\n",
        "  loss_metric.reset_states()\n",
        "  accuracy_metric.reset_states()\n",
        "\n",
        "  for inputs, labels in train_data:\n",
        "    train_step(inputs, labels)\n",
        "  # Get the metric results\n",
        "  mean_loss=loss_metric.result()\n",
        "  mean_accuracy = accuracy_metric.result()\n",
        "\n",
        "  print('Epoch: ', epoch)\n",
        "  print('  loss:     {:.3f}'.format(mean_loss))\n",
        "  print('  accuracy: {:.3f}'.format(mean_accuracy))\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "9VwIAdQygzFz"
      },
      "source": [
        "<a id=\"keras_metric_names\"></a>\n",
        "\n",
        "### Keras メトリック名"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "SKMlNr7OsRdQ"
      },
      "source": [
        "TensorFlow 2.0では、Keras モデルはメトリック名の処理に関してより一貫性があります。\n",
        "\n",
        "メトリックリストで文字列を渡すと、*まさにその*文字列がメトリックの`name`として使用されます。これらの名前は<br>`model.fit`によって返される履歴オブジェクトと、`keras.callbacks`に渡されるログに表示されます。これはメトリックリストで渡した文字列に設定されています。 "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "1iODIsGDgyYd"
      },
      "outputs": [],
      "source": [
        "model.compile(\n",
        "    optimizer = tf.keras.optimizers.Adam(0.001),\n",
        "    loss = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),\n",
        "    metrics = ['acc', 'accuracy', tf.keras.metrics.SparseCategoricalAccuracy(name=\"my_accuracy\")])\n",
        "history = model.fit(train_data)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "8oGzs_TlisKJ"
      },
      "outputs": [],
      "source": [
        "history.history.keys()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "g3akhzRCylSk"
      },
      "source": [
        "これは`metrics=[\"accuracy\"]`を渡すと`dict_keys(['loss', 'acc'])`になっていた、以前のバージョンとは異なります。 "
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Hf718XCgDAGJ"
      },
      "source": [
        "### Keras オプティマイザ"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "A6El-NxAQ8aF"
      },
      "source": [
        "`v1.train.AdamOptimizer`や`v1.train.GradientDescentOptimizer`などの`v1.train`内のオプティマイザは、`tf.keras.optimizers`内に同等のものを持ちます。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "qgP89WdSDQx-"
      },
      "source": [
        "#### `v1.train`を`keras.optimizers`に変換する\n",
        "\n",
        "オプティマイザを変換する際の注意事項を次に示します。\n",
        "\n",
        "- オプティマイザをアップグレードすると、[古いチェックポイントとの互換性がなくなる可能性があります](#checkpoints)。\n",
        "- epsilon のデフォルトは全て`1e-8`ではなく`1e-7`になりました。（これはほとんどのユースケースで無視できます。）\n",
        "- `v1.train.GradientDescentOptimizer`は`tf.keras.optimizers.SGD`で直接置き換えが可能です。\n",
        "- `v1.train.MomentumOptimizer`はモメンタム引数（`tf.keras.optimizers.SGD(..., momentum=...)`）を使用して`SGD`オプティマイザで直接置き換えが可能です。\n",
        "- `v1.train.AdamOptimizer`を変換して`tf.keras.optimizers.Adam`を使用することが可能です。<code>beta1</code>引数と`beta2`引数の名前は、`beta_1`と`beta_2`に変更されています。\n",
        "- `v1.train.RMSPropOptimizer`は`tf.keras.optimizers.RMSprop`に変換可能です。 `decay`引数の名前は`rho`に変更されています。\n",
        "- `v1.train.AdadeltaOptimizer`は`tf.keras.optimizers.Adadelta`に直接変換が可能です。\n",
        "- `tf.train.AdagradOptimizer`は `tf.keras.optimizers.Adagrad`に直接変換が可能です。\n",
        "- `tf.train.FtrlOptimizer`は`tf.keras.optimizers.Ftrl`に直接変換が可能です。`accum_name`および`linear_name`引数は削除されています。\n",
        "- `tf.contrib.AdamaxOptimizer`と`tf.contrib.NadamOptimizer`は `tf.keras.optimizers.Adamax`と`tf.keras.optimizers.Nadam`に直接変換が可能です。`beta1`引数と`beta2`引数の名前は、`beta_1`と`beta_2`に変更されています。\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Ef60-wJ2bR3l"
      },
      "source": [
        "#### 一部の`tf.keras.optimizers`の新しいデフォルト\n",
        "\n",
        "<a id=\"keras_optimizer_lr\"></a>\n",
        "\n",
        "警告: モデルの収束挙動に変化が見られる場合には、デフォルトの学習率を確認してください。\n",
        "\n",
        "`optimizers.SGD`、`optimizers.Adam`、または`optimizers.RMSprop`に変更はありません。\n",
        "\n",
        "次のデフォルトの学習率が変更されました。\n",
        "\n",
        "- `optimizers.Adagrad` 0.01 から 0.001 へ\n",
        "- `optimizers.Adadelta` 1.0 から 0.001 へ\n",
        "- `optimizers.Adamax` 0.002 から 0.001 へ\n",
        "- `optimizers.Nadam` 0.002 から 0.001 へ"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "5Cf1ks48Q3uc"
      },
      "source": [
        "### TensorBoard"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "0tx7FyM_RHwJ"
      },
      "source": [
        "TensorFlow 2 には、TensorBoard で視覚化するための要約データを記述するために使用される`tf.summary` API の大幅な変更が含まれています。新しい`tf.summary`の概要については、TensorFlow 2 API を使用した[複数のチュートリアル](https://www.tensorflow.org/tensorboard/get_started)があります。これには、[TensorBoard TensorFlow 2 移行ガイド](https://www.tensorflow.org/tensorboard/migrate)も含まれています。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "JmMLBKs66DeA"
      },
      "source": [
        "## 保存 & 読み込み\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "5_QKn3Kl6TUu"
      },
      "source": [
        "<a id=\"checkpoints\"></a>\n",
        "\n",
        "### チェックポイントの互換性\n",
        "\n",
        "TensorFlow 2.0 は[オブジェクトベースのチェックポイント](checkpoint.ipynb)を使用します。\n",
        "\n",
        "古いスタイルの名前ベースのチェックポイントは、注意を払えば依然として読み込むことができます。コード変換プロセスは変数名変更という結果になるかもしれませんが、回避方法はあります。\n",
        "\n",
        "最も単純なアプローチは、チェックポイント内の名前と新しいモデルの名前を揃えて並べることです。\n",
        "\n",
        "- 変数にはすべて依然として設定が可能な`name`引数があります。\n",
        "- Keras モデルはまた `name`引数を取り、それらの変数のためのプレフィックスとして設定されます。\n",
        "- `v1.name_scope`関数は、変数名のプレフィックスの設定に使用できます。これは`tf.variable_scope`とは大きく異なります。これは名前だけに影響するもので、変数と再利用の追跡はしません。\n",
        "\n",
        "ご利用のユースケースで動作しない場合は、`v1.train.init_from_checkpoint`を試してみてください。これは`assignment_map`引数を取り、古い名前から新しい名前へのマッピングを指定します。\n",
        "\n",
        "注意 : [読み込みを遅延](checkpoint.ipynb#loading_mechanics)できるオブジェクトベースのチェックポイントとは異なり、名前ベースのチェックポイントは関数が呼び出される時に全ての変数が構築されていることを要求します。一部のモデルは、`build`を呼び出すかデータのバッチでモデルを実行するまで変数の構築を遅延します。\n",
        "\n",
        "[TensorFlow Estimatorリポジトリ](https://github.com/tensorflow/estimator/blob/master/tensorflow_estimator/python/estimator/tools/checkpoint_converter.py)には事前作成された Estimator のチェックポイントを TensorFlow 1.X から 2.0 にアップグレードするための[変換ツール](#checkpoint_converter)が含まれています。これは、同様のユースケースのツールを構築する方法の例として有用な場合があります。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "_ONjobDD6Uur"
      },
      "source": [
        "### 保存されたモデルの互換性\n",
        "\n",
        "保存されたモデルには、互換性に関する重要な考慮事項はありません。\n",
        "\n",
        "- TensorFlow 1.x saved_models は TensorFlow 2.x で動作します。\n",
        "- TensorFlow 2.x saved_models は全ての演算がサポートされていれば TensorFlow 1.x で動作します。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "-KpXprsf1tyb"
      },
      "source": [
        "### Graph.pb または Graph.pbtxt "
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Tz4eAAGY19MM"
      },
      "source": [
        "未加工の`Graph.pb`ファイルを TensorFlow 2.0 にアップグレードする簡単な方法はありません。確実な方法は、ファイルを生成したコードをアップグレードすることです。\n",
        "\n",
        "ただし、「凍結グラフ」（変数が定数に変換された`tf.Graph`）がある場合、`v1.wrap_function`を使用して[`concrete_function`](https://tensorflow.org/guide/concrete_function)への変換が可能です。\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "1xl_fFhs1ur6"
      },
      "outputs": [],
      "source": [
        "def wrap_frozen_graph(graph_def, inputs, outputs):\n",
        "  def _imports_graph_def():\n",
        "    tf.compat.v1.import_graph_def(graph_def, name=\"\")\n",
        "  wrapped_import = tf.compat.v1.wrap_function(_imports_graph_def, [])\n",
        "  import_graph = wrapped_import.graph\n",
        "  return wrapped_import.prune(\n",
        "      tf.nest.map_structure(import_graph.as_graph_element, inputs),\n",
        "      tf.nest.map_structure(import_graph.as_graph_element, outputs))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "bQHGXyYC4GT-"
      },
      "source": [
        "例えば、次のような凍結された Inception v1 グラフ（2016 年）があります。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "obfto7Bp3hHj"
      },
      "outputs": [],
      "source": [
        "path = tf.keras.utils.get_file(\n",
        "    'inception_v1_2016_08_28_frozen.pb',\n",
        "    'http://storage.googleapis.com/download.tensorflow.org/models/inception_v1_2016_08_28_frozen.pb.tar.gz',\n",
        "    untar=True)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "FHE3Ot4gSCJg"
      },
      "source": [
        "`tf.GraphDef`を読み込みます。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "HqL_OTwr4n20"
      },
      "outputs": [],
      "source": [
        "graph_def = tf.compat.v1.GraphDef()\n",
        "loaded = graph_def.ParseFromString(open(path,'rb').read())"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "T9ai6Kh6SsQ4"
      },
      "source": [
        "これを`concrete_function`にラップします。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "pajiVteo6H0U"
      },
      "outputs": [],
      "source": [
        "inception_func = wrap_frozen_graph(\n",
        "    graph_def, inputs='input:0',\n",
        "    outputs='InceptionV1/InceptionV1/Mixed_3b/Branch_1/Conv2d_0a_1x1/Relu:0')"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "FvknOO-MSw4n"
      },
      "source": [
        "入力としてテンソルを渡します。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "gsPSIjAE7nry"
      },
      "outputs": [],
      "source": [
        "input_img = tf.ones([1,224,224,3], dtype=tf.float32)\n",
        "inception_func(input_img).shape"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ewl9P3oZ6ZtR"
      },
      "source": [
        "## Estimator"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "YprVP9g3l6eG"
      },
      "source": [
        "### Estimator でトレーニングする\n",
        "\n",
        "Estimator は TensorFlow 2.0 でサポートされています。\n",
        "\n",
        "Estimator を使用する際には、TensorFlow 1.x. からの`input_fn()`、`tf.estimator.TrainSpec`、`tf.estimator.EvalSpec`を使用できます。\n",
        "\n",
        "ここに train と evaluate specs を伴う `input_fn` を使用する例があります。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "N5kZeJsF8lS2"
      },
      "source": [
        "#### input_fn と train/eval specs を作成する"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "AOlXGO4J6jDh"
      },
      "outputs": [],
      "source": [
        "# Define the estimator's input_fn\n",
        "def input_fn():\n",
        "  datasets, info = tfds.load(name='mnist', with_info=True, as_supervised=True)\n",
        "  mnist_train, mnist_test = datasets['train'], datasets['test']\n",
        "\n",
        "  BUFFER_SIZE = 10000\n",
        "  BATCH_SIZE = 64\n",
        "\n",
        "  def scale(image, label):\n",
        "    image = tf.cast(image, tf.float32)\n",
        "    image /= 255\n",
        "\n",
        "    return image, label[..., tf.newaxis]\n",
        "\n",
        "  train_data = mnist_train.map(scale).shuffle(BUFFER_SIZE).batch(BATCH_SIZE)\n",
        "  return train_data.repeat()\n",
        "\n",
        "# Define train &amp; eval specs\n",
        "train_spec = tf.estimator.TrainSpec(input_fn=input_fn,\n",
        "                                    max_steps=STEPS_PER_EPOCH * NUM_EPOCHS)\n",
        "eval_spec = tf.estimator.EvalSpec(input_fn=input_fn,\n",
        "                                  steps=STEPS_PER_EPOCH)\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "_o6J48Nj9H5c"
      },
      "source": [
        "### Keras モデル定義を使用する"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "IXCQdhGq9SbB"
      },
      "source": [
        "TensorFlow 2.0 で Estimator を構築する方法には、いくつかの違いがあります。\n",
        "\n",
        "モデルは Keras を使用して定義することを推奨します。次に`tf.keras.estimator.model_to_estimator`ユーティリティを使用して、モデルを Estimator に変更します。次のコードは Estimator を作成してトレーニングする際に、このユーティリティをどのように使用するかを示します。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "aelsClm3Cq4I"
      },
      "outputs": [],
      "source": [
        "def make_model():\n",
        "  return tf.keras.Sequential([\n",
        "    tf.keras.layers.Conv2D(32, 3, activation='relu',\n",
        "                           kernel_regularizer=tf.keras.regularizers.l2(0.02),\n",
        "                           input_shape=(28, 28, 1)),\n",
        "    tf.keras.layers.MaxPooling2D(),\n",
        "    tf.keras.layers.Flatten(),\n",
        "    tf.keras.layers.Dropout(0.1),\n",
        "    tf.keras.layers.Dense(64, activation='relu'),\n",
        "    tf.keras.layers.BatchNormalization(),\n",
        "    tf.keras.layers.Dense(10)\n",
        "  ])"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "HJb6f8dtl6rr"
      },
      "outputs": [],
      "source": [
        "model = make_model()\n",
        "\n",
        "model.compile(optimizer='adam',\n",
        "              loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),\n",
        "              metrics=['accuracy'])\n",
        "\n",
        "estimator = tf.keras.estimator.model_to_estimator(\n",
        "  keras_model = model\n",
        ")\n",
        "\n",
        "tf.estimator.train_and_evaluate(estimator, train_spec, eval_spec)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "RBoa-xXPs4rD"
      },
      "source": [
        "注意 : Keras で重み付きメトリクスを作成し、`model_to_estimator`を使用してそれらを Estimator API で重み付きメトリクスを変換することはサポートされません。それらのメトリクスは、`add_metrics`関数を使用して Estimator 仕様で直接作成する必要があります。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "-ptTxL1q6flL"
      },
      "source": [
        "### カスタム `model_fn` を使用する\n",
        "\n",
        "保守する必要がある既存のカスタム Estimator `model_fn` を持つ場合には、`model_fn`を変換して Keras モデルを使用できるようにすることが可能です。\n",
        "\n",
        "しかしながら、互換性の理由から、カスタム`model_fn`は依然として1.x スタイルのグラフモードで動作します。これは eager execution はなく自動制御依存性もないことも意味します。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Avgqf8IKfd51"
      },
      "source": [
        "<a name=\"minimal_changes\"></a>\n",
        "\n",
        "#### 最小限の変更で model_fn をカスタマイズする\n",
        "\n",
        "TensorFlow 2.0 でカスタム`model_fn`を動作させるには、既存のコードの変更を最小限に留めたい場合、`optimizers`や`metrics`などの`tf.compat.v1`シンボルを使用することができます。\n",
        "\n",
        "カスタム`model_fn`で Keras モデルを使用することは、それをカスタムトレーニングループで使用することに類似しています。\n",
        "\n",
        "- `mode`引数を基に、`training`段階を適切に設定します。\n",
        "- モデルの`trainable_variables`をオプティマイザに明示的に渡します。\n",
        "\n",
        "しかし、[カスタムループ](#custom_loop)と比較して、重要な違いがあります。\n",
        "\n",
        "- `Model.losses`を使用する代わりに`Model.get_losses_for`を使用して損失を抽出します。\n",
        "- `Model.get_updates_for`を使用してモデルの更新を抽出します。\n",
        "\n",
        "注意 : 「更新」は各バッチの後にモデルに適用される必要がある変更です。例えば、`layers.BatchNormalization`レイヤーの平均と分散の移動平均などです。\n",
        "\n",
        "次のコードはカスタム`model_fn`から Estimator を作成し、これらの懸念事項を全て示しています。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "iY16eZKW606-"
      },
      "outputs": [],
      "source": [
        "def my_model_fn(features, labels, mode):\n",
        "  model = make_model()\n",
        "\n",
        "  optimizer = tf.compat.v1.train.AdamOptimizer()\n",
        "  loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)\n",
        "\n",
        "  training = (mode == tf.estimator.ModeKeys.TRAIN)\n",
        "  predictions = model(features, training=training)\n",
        "\n",
        "  if mode == tf.estimator.ModeKeys.PREDICT:\n",
        "    return tf.estimator.EstimatorSpec(mode=mode, predictions=predictions)\n",
        "\n",
        "  reg_losses = model.get_losses_for(None) + model.get_losses_for(features)\n",
        "  total_loss=loss_fn(labels, predictions) + tf.math.add_n(reg_losses)\n",
        "\n",
        "  accuracy = tf.compat.v1.metrics.accuracy(labels=labels,\n",
        "                                           predictions=tf.math.argmax(predictions, axis=1),\n",
        "                                           name='acc_op')\n",
        "\n",
        "  update_ops = model.get_updates_for(None) + model.get_updates_for(features)\n",
        "  minimize_op = optimizer.minimize(\n",
        "      total_loss,\n",
        "      var_list=model.trainable_variables,\n",
        "      global_step=tf.compat.v1.train.get_or_create_global_step())\n",
        "  train_op = tf.group(minimize_op, update_ops)\n",
        "\n",
        "  return tf.estimator.EstimatorSpec(\n",
        "    mode=mode,\n",
        "    predictions=predictions,\n",
        "    loss=total_loss,\n",
        "    train_op=train_op, eval_metric_ops={'accuracy': accuracy})\n",
        "\n",
        "# Create the Estimator &amp; Train\n",
        "estimator = tf.estimator.Estimator(model_fn=my_model_fn)\n",
        "tf.estimator.train_and_evaluate(estimator, train_spec, eval_spec)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "XVxHmU2ccfAG"
      },
      "source": [
        "#### TensorFlow 2.0 シンボルで`model_fn`をカスタマイズする\n",
        "\n",
        "TensorFlow 1.x シンボルを全て削除し、カスタム`model_fn` をネイティブの TensorFlow 2.0 にアップグレードする場合は、オプティマイザとメトリクスを`tf.keras.optimizers`と`tf.keras.metrics`にアップグレードする必要があります。\n",
        "\n",
        "カスタム`model_fn`では、上記の[変更](#minimal_changes)に加えて、さらにアップグレードを行う必要があります。\n",
        "\n",
        "- `v1.train.Optimizer`の代わりに[`tf.keras.optimizers`](https://www.tensorflow.org/versions/r2.0/api_docs/python/tf/keras/optimizers)を使用します。\n",
        "- モデルの`trainable_variables`を`tf.keras.optimizers`に明示的に渡します。\n",
        "- `train_op/minimize_op`を計算するには、\n",
        "    - 損失がスカラー損失`Tensor`（呼び出し不可）の場合は、`Optimizer.get_updates()`を使用します。返されるリストの最初の要素は目的とする`train_op/minimize_op`です。\n",
        "    - 損失が呼び出し可能（関数など）な場合は、`Optimizer.minimize()`を使用して`train_op/minimize_op`を取得します。\n",
        "- 評価には`tf.compat.v1.metrics`の代わりに[`tf.keras.metrics`](https://www.tensorflow.org/api_docs/python/tf/keras/metrics)を使用します。\n",
        "\n",
        "上記の`my_model_fn`の例では、2.0 シンボルの移行されたコードは次のように表示されます。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "uf8J3nloeze2"
      },
      "outputs": [],
      "source": [
        "def my_model_fn(features, labels, mode):\n",
        "  model = make_model()\n",
        "\n",
        "  training = (mode == tf.estimator.ModeKeys.TRAIN)\n",
        "  loss_obj = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)\n",
        "  predictions = model(features, training=training)\n",
        "\n",
        "  # Get both the unconditional losses (the None part)\n",
        "  # and the input-conditional losses (the features part).\n",
        "  reg_losses = model.get_losses_for(None) + model.get_losses_for(features)\n",
        "  total_loss=loss_obj(labels, predictions) + tf.math.add_n(reg_losses)\n",
        "\n",
        "  # Upgrade to tf.keras.metrics.\n",
        "  accuracy_obj = tf.keras.metrics.Accuracy(name='acc_obj')\n",
        "  accuracy = accuracy_obj.update_state(\n",
        "      y_true=labels, y_pred=tf.math.argmax(predictions, axis=1))\n",
        "\n",
        "  train_op = None\n",
        "  if training:\n",
        "    # Upgrade to tf.keras.optimizers.\n",
        "    optimizer = tf.keras.optimizers.Adam()\n",
        "    # Manually assign tf.compat.v1.global_step variable to optimizer.iterations\n",
        "    # to make tf.compat.v1.train.global_step increased correctly.\n",
        "    # This assignment is a must for any `tf.train.SessionRunHook` specified in\n",
        "    # estimator, as SessionRunHooks rely on global step.\n",
        "    optimizer.iterations = tf.compat.v1.train.get_or_create_global_step()\n",
        "    # Get both the unconditional updates (the None part)\n",
        "    # and the input-conditional updates (the features part).\n",
        "    update_ops = model.get_updates_for(None) + model.get_updates_for(features)\n",
        "    # Compute the minimize_op.\n",
        "    minimize_op = optimizer.get_updates(\n",
        "        total_loss,\n",
        "        model.trainable_variables)[0]\n",
        "    train_op = tf.group(minimize_op, *update_ops)\n",
        "\n",
        "  return tf.estimator.EstimatorSpec(\n",
        "    mode=mode,\n",
        "    predictions=predictions,\n",
        "    loss=total_loss,\n",
        "    train_op=train_op,\n",
        "    eval_metric_ops={'Accuracy': accuracy_obj})\n",
        "\n",
        "# Create the Estimator &amp; Train.\n",
        "estimator = tf.estimator.Estimator(model_fn=my_model_fn)\n",
        "tf.estimator.train_and_evaluate(estimator, train_spec, eval_spec)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "g1l6VnOTodfA"
      },
      "source": [
        "###  事前作成された Estimator\n",
        "\n",
        "`tf.estimator.DNN*`、`tf.estimator.Linear*`、 `tf.estimator.DNNLinearCombined*`のファミリーに含まれる[事前作成された Estimator](https://www.tensorflow.org/guide/premade_estimators) は、依然として TensorFlow 2.0 API でもサポートされていますが、一部の引数が変更されています。\n",
        "\n",
        "1. `input_layer_partitioner`: 2.0 で削除されました。\n",
        "2. `loss_reduction`: `tf.compat.v1.losses.Reduction`の代わりに`tf.keras.losses.Reduction`に更新されました。デフォルト値も`tf.compat.v1.losses.Reduction.SUM`から`tf.keras.losses.Reduction.SUM_OVER_BATCH_SIZE`に変更されています。\n",
        "3. `optimizer`、`dnn_optimizer`、`linear_optimizer`: これらの引数は`tf.compat.v1.train.Optimizer`の代わりに`tf.keras.optimizers`に更新されています。\n",
        "\n",
        "上記の変更を移行するには :\n",
        "\n",
        "1. TF 2.0 では[`配布戦略`](https://www.tensorflow.org/guide/distributed_training)が自動的に処理するため、`input_layer_partitioner`の移行は必要ありません。\n",
        "2. `loss_reduction`については[`tf.keras.losses.Reduction`](https://www.tensorflow.org/versions/r2.0/api_docs/python/tf/keras/losses/Reduction)でサポートされるオプションを確認してください。\n",
        "3. `optimizer`引数については、`optimizer`、`dnn_optimizer`、`linear_optimizer`引数を渡さない場合、または`optimizer`引数をコード内の内の`string`として指定する場合は、何も変更する必要はありません。デフォルトで`tf.keras.optimizers`を使用します。それ以外の場合は、`tf.compat.v1.train.Optimizer`から対応する[`tf.keras.optimizers`](https://www.tensorflow.org/versions/r2.0/api_docs/python/tf/keras/optimizers)に更新する必要があります。\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "v0Kljg-AHyqv"
      },
      "source": [
        "#### チェックポイントコンバータ\n",
        "\n",
        "<a id=\"checkpoint_converter\"></a>\n",
        "\n",
        "`tf.keras.optimizers`は異なる変数セットを生成してチェックポイントに保存するするため、`keras.optimizers`への移行は TensorFlow 1.x を使用して保存されたチェックポイントを壊してしまいます。TensorFlow 2.0 への移行後に古いチェックポイントを再利用できるようにするには、[チェックポイントコンバータツール](https://github.com/tensorflow/estimator/blob/master/tensorflow_estimator/python/estimator/tools/checkpoint_converter.py)をお試しください。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "h9FiYN9mIPli"
      },
      "outputs": [],
      "source": [
        "! curl -O https://raw.githubusercontent.com/tensorflow/estimator/master/tensorflow_estimator/python/estimator/tools/checkpoint_converter.py"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "DMc6zDJaJwNw"
      },
      "source": [
        "ツールにはヘルプが組み込まれています。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "9JNZFX3rJLXv"
      },
      "outputs": [],
      "source": [
        "! python checkpoint_converter.py -h"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "dt8ct9XCFqls"
      },
      "source": [
        "<a id=\"tensorshape\"></a>\n",
        "\n",
        "## TensorShape\n",
        "\n",
        "このクラスは`tf.compat.v1.Dimension`オブジェクトの代わりに`int`を保持することにより単純化されました。従って、`.value()`を呼び出して`int`を取得する必要はありません。\n",
        "\n",
        "個々の`tf.compat.v1.Dimension`オブジェクトは依然として`tf.TensorShape.dims`からアクセス可能です。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "x36cWcmM8Eu1"
      },
      "source": [
        "以下に TensorFlow 1.x と TensorFlow 2.0 間の違いを示します。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "PbpD-kHOZR4A"
      },
      "outputs": [],
      "source": [
        "# Create a shape and choose an index\n",
        "i = 0\n",
        "shape = tf.TensorShape([16, None, 256])\n",
        "shape"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "kDFck03neNy0"
      },
      "source": [
        "もし TensorFlow 1.x で次を使っていた場合:\n",
        "\n",
        "```python\n",
        "value = shape[i].value\n",
        "```\n",
        "\n",
        "TensorFlow 2.0 では次のようにします:\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "KuR73QGEeNdH"
      },
      "outputs": [],
      "source": [
        "value = shape[i]\n",
        "value"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "bPWPNKRiZmkd"
      },
      "source": [
        "もし TensorFlow 1.x で次を使っていた場合:\n",
        "\n",
        "```python\n",
        "for dim in shape:     value = dim.value     print(value)\n",
        "```\n",
        "\n",
        "TensorFlow 2.0 では次のようにします:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "y6s0vuuprJfc"
      },
      "outputs": [],
      "source": [
        "for value in shape:\n",
        "  print(value)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "YpRgngu3Zw-A"
      },
      "source": [
        "もし TensorFlow 1.x で次を使っていた場合（あるいは任意の他の次元のメソッドを使用したのであれば）:\n",
        "\n",
        "```python\n",
        "dim = shape[i] dim.assert_is_compatible_with(other_dim)\n",
        "```\n",
        "\n",
        "TensorFlow 2.0 では次のようにします:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "LpViGEcUZDGX"
      },
      "outputs": [],
      "source": [
        "other_dim = 16\n",
        "Dimension = tf.compat.v1.Dimension\n",
        "\n",
        "if shape.rank is None:\n",
        "  dim = Dimension(None)\n",
        "else:\n",
        "  dim = shape.dims[i]\n",
        "dim.is_compatible_with(other_dim) # or any other dimension method"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "GaiGe36dOdZ_"
      },
      "outputs": [],
      "source": [
        "shape = tf.TensorShape(None)\n",
        "\n",
        "if shape:\n",
        "  dim = shape.dims[i]\n",
        "  dim.is_compatible_with(other_dim) # or any other dimension method"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "3kLLY0I3PI-l"
      },
      "source": [
        "`tf.TensorShape`のブール型の値は、階数が既知の場合は`True`で、そうでない場合は`False`です。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "-Ow1ndKpOnJd"
      },
      "outputs": [],
      "source": [
        "print(bool(tf.TensorShape([])))      # Scalar\n",
        "print(bool(tf.TensorShape([0])))     # 0-length vector\n",
        "print(bool(tf.TensorShape([1])))     # 1-length vector\n",
        "print(bool(tf.TensorShape([None])))  # Unknown-length vector\n",
        "print(bool(tf.TensorShape([1, 10, 100])))       # 3D tensor\n",
        "print(bool(tf.TensorShape([None, None, None]))) # 3D tensor with no known dimensions\n",
        "print()\n",
        "print(bool(tf.TensorShape(None)))  # A tensor with unknown rank."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "8u63n5S7Y9IX"
      },
      "source": [
        "## その他の変更点\n",
        "\n",
        "- `tf.colocate_with`を削除する : TensorFlow のデバイス配置アルゴリズムが大幅に改善されたため、これはもう必要ありません。削除したことによってパフォーマンスが低下する場合には、[バグを報告してください](https://github.com/tensorflow/tensorflow/issues)。\n",
        "\n",
        "- `v1.ConfigProto`の使用を`tf.config`の同等の関数に置き換える。\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "vKX6AdTAQhB-"
      },
      "source": [
        "## まとめ\n",
        "\n",
        "全体のプロセスは次のとおりです。\n",
        "\n",
        "1. アップグレードスクリプトを実行する。\n",
        "2. contrib シンボルを除去する。\n",
        "3. モデルをオブジェクト指向スタイル (Keras) に切り替える。\n",
        "4. 可能なところでは `tf.keras`または`tf.estimator`トレーニングと評価ループを使用する。\n",
        "5. そうでない場合はカスタムループを使用してよいが、セッション＆コレクションの回避を確実にする。\n",
        "\n",
        "コードを慣用的な TensorFlow 2.0 に変換するには少し作業を要しますが、変更するごとに次のような結果が得られます。\n",
        "\n",
        "- コード行が減少する。\n",
        "- 明瞭さと簡略性が向上する。\n",
        "- デバッグが容易になる。\n"
      ]
    }
  ],
  "metadata": {
    "colab": {
      "collapsed_sections": [],
      "name": "migrate.ipynb",
      "toc_visible": true
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
